package mockito;

import org.junit.Assert;
import org.junit.Test;
import org.springframework.cglib.beans.BeanCopier;
import org.springframework.cglib.beans.BeanGenerator;
import org.springframework.cglib.beans.ImmutableBean;
import org.springframework.cglib.proxy.*;

import java.lang.reflect.Method;

/**
 * @author      : yang.xp
 * @date        : 2021/10/16 14:53
 * @description : 原文地址 https://dzone.com/articles/cglib-missing-manual
 */

public class SampleClass {
	public void test() {
		System.out.println("hello world");
	}
	public void test2() {
		System.out.println("hello world2");
	}


	public String testR(Object object) {
		return "hello world";
	}

	public static void main(String[] args) {
		org.springframework.cglib.proxy.Enhancer enhancer = new org.springframework.cglib.proxy.Enhancer();
		enhancer.setSuperclass(SampleClass.class);
		enhancer.setCallback((MethodInterceptor) (obj, method, args1, proxy) -> {
			System.out.println("before method run...");
			Object result = proxy.invokeSuper(obj, args1);
			System.out.println("after method run...");
			return result;
		});
		SampleClass sample = (SampleClass) enhancer.create();
		sample.test();
		sample.test2();

	}

	@Test
	public void testFixedValue() {
		org.springframework.cglib.proxy.Enhancer enhancer = new org.springframework.cglib.proxy.Enhancer();
		enhancer.setSuperclass(SampleClass.class);
		enhancer.setCallback(new org.springframework.cglib.proxy.FixedValue() {
			@Override
			public Object loadObject() throws Exception {
				return "Hello cglib";
			}
		});
		SampleClass proxy = (SampleClass) enhancer.create();
		System.out.println(proxy.testR(null)); //拦截test，输出Hello cglib
		System.out.println(proxy.toString());
		System.out.println(proxy.getClass());
		System.out.println(proxy.hashCode());
	}

	@Test
	public void testCallbackFilter() throws Exception{
		org.springframework.cglib.proxy.Enhancer enhancer = new Enhancer();
		CallbackHelper callbackHelper = new CallbackHelper(SampleClass.class, new Class[0]) {
			@Override
			protected Object getCallback(Method method) {
				if(method.getDeclaringClass() != Object.class && method.getReturnType() == String.class){
					return new FixedValue() {
						@Override
						public Object loadObject() throws Exception {
							return "Hello cglib";
						}
					};
				}else{
					return NoOp.INSTANCE;
				}
			}
		};
		enhancer.setSuperclass(SampleClass.class);
		enhancer.setCallbackFilter(callbackHelper);
		enhancer.setCallbacks(callbackHelper.getCallbacks());
		SampleClass proxy = (SampleClass) enhancer.create();
		Assert.assertEquals("Hello cglib", proxy.testR(null));
		Assert.assertNotEquals("Hello cglib",proxy.toString());
		System.out.println(proxy.hashCode());
	}

	@Test(expected = IllegalStateException.class)
	public void testImmutableBean() throws Exception {
		SampleBean bean = new SampleBean();
		bean.setValue("Hello world");
		SampleBean immutableBean = (SampleBean) ImmutableBean.create(bean); //创建不可变类
		Assert.assertEquals("Hello world", immutableBean.getValue());
		bean.setValue("Hello world, again"); //可以通过底层对象来进行修改
		Assert.assertEquals("Hello world, again", immutableBean.getValue());
		immutableBean.setValue("Hello cglib"); //直接修改将throw exception
	}

	@Test
	public void testBeanGenerator() throws Exception{
		BeanGenerator beanGenerator = new BeanGenerator();
		beanGenerator.addProperty("value",String.class);
		Object myBean = beanGenerator.create();
		Method setter = myBean.getClass().getMethod("setValue",String.class);
		setter.invoke(myBean,"Hello cglib");

		Method getter = myBean.getClass().getMethod("getValue");
		Assert.assertEquals("Hello cglib",getter.invoke(myBean));
	}

	@Test
	public void testBeanCopier() throws Exception{
		BeanCopier copier = BeanCopier.create(SampleBean.class, OtherSampleBean.class, false);//设置为true，则使用converter
		SampleBean myBean = new SampleBean();
		myBean.setValue("Hello cglib");
		OtherSampleBean otherBean = new OtherSampleBean();
		copier.copy(myBean, otherBean, null); //设置为true，则传入converter指明怎么进行转换
		Assert.assertEquals("Hello cglib", otherBean.getValue());
	}
}

